using RaceHFTools.BluetoothLE.Bean;
using System;
using System.Threading.Tasks;

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace RaceHFTools.Pages.Tweak
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class TweakGnssPage : ContentPage
    {
        private readonly Bean bean;

        public TweakGnssPage(Bean bean)
        {
            InitializeComponent();

            this.bean = bean;
        }

        #region 事件处理
        private bool rate_set_done, gnss_set_done, navx5_set_done;

        void OnAllSetDone()
        {
            if (rate_set_done && gnss_set_done && navx5_set_done)
            {
                Device.BeginInvokeOnMainThread(async () => await DisplayAlert("卫星定位设置", "设置完毕", "确定"));
            }
        }

        void ResetAllFlags()
        {
            rate_set_done = false;
            gnss_set_done = false;
            navx5_set_done = false;
        }

        void OnRateGet(uint rate)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                switch (rate)
                {
                    case 1: cbxGnss1Hz.IsChecked = true; break;
                    case 2: cbxGnss2Hz.IsChecked = true; break;
                    case 5: cbxGnss5Hz.IsChecked = true; break;
                    case 10: cbxGnss10Hz.IsChecked = true; break;
                    case 18: cbxGnss18Hz.IsChecked = true; break;
                    case 20: cbxGnss20Hz.IsChecked = true; break;
                }
            });
        }

        void OnGnssGet(bool gps, bool glonass, bool galileo, bool beidou)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                if (gps) cbxGnssGps.IsChecked = true;
                if (glonass) cbxGnssGlonass.IsChecked = true;
                if (galileo) cbxGnssGalileo.IsChecked = true;
                if (beidou) cbxGnssBeidou.IsChecked = true;
            });
        }

        void OnNavx5Get(uint min_sv, uint max_sv, uint min_noise)
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                etyGnssSvMin.Text = min_sv.ToString();
                etyGnssSvMax.Text = max_sv.ToString();
                etyGnssNoiseMin.Text = min_noise.ToString();
            });
        }

        void OnRateSet(bool success)
        {
            rate_set_done = success;
            OnAllSetDone();
        }

        void OnGnssSet(bool success)
        {
            gnss_set_done = success;
            OnAllSetDone();
        }

        void OnNavx5Set(bool success)
        {
            navx5_set_done = success;
            OnAllSetDone();
        }

        async Task<bool> DoRateSet()
        {
            uint rate = 0;

            if (cbxGnss1Hz.IsChecked) rate = 1;
            else if (cbxGnss2Hz.IsChecked) rate = 2;
            else if (cbxGnss5Hz.IsChecked) rate = 5;
            else if (cbxGnss10Hz.IsChecked) rate = 10;
            else if (cbxGnss18Hz.IsChecked) rate = 18;
            else if (cbxGnss20Hz.IsChecked) rate = 20;

            if (rate == 0)
            {
                Device.BeginInvokeOnMainThread(async () => await DisplayAlert("定位卫星", "请选择刷新率", "确定"));
                return false;
            }

            await bean.Tweak.SetGnssRate(rate);

            return true;
        }

        async Task<bool> DoGnssSet()
        {
            bool gps = cbxGnssGps.IsChecked;
            bool glonass = cbxGnssGlonass.IsChecked;
            bool galileo = cbxGnssGalileo.IsChecked;
            bool beidou = cbxGnssBeidou.IsChecked;

            if (!gps && !glonass && !galileo && !beidou)
            {
                Device.BeginInvokeOnMainThread(async () => await DisplayAlert("定位卫星", "至少勾选一种定位卫星", "确定"));
                return false;
            }

            await bean.Tweak.SetGnssGnss(gps, glonass, galileo, beidou);

            return true;
        }

        async Task<bool> DoNavx5Set()
        {
            if (!uint.TryParse(etyGnssSvMin.Text.Trim(), out uint min_sv) ||
                !uint.TryParse(etyGnssSvMax.Text.Trim(), out uint max_sv) ||
                !uint.TryParse(etyGnssNoiseMin.Text.Trim(), out uint min_noise))
            {
                Device.BeginInvokeOnMainThread(async () => await DisplayAlert("GNSS", "NAVX5参数错误", "确定"));
                return false;
            }

            await bean.Tweak.SetGnssNavx5(min_sv, max_sv, min_noise);

            return true;
        }
        #endregion

        #region OnAppearing/OnDisappearing
        protected override void OnAppearing()
        {
            base.OnAppearing();

            bean.Tweak.GnssGetRateEvent += OnRateGet;
            bean.Tweak.GnssGetGnssEvent += OnGnssGet;
            bean.Tweak.GnssGetNavx5Event += OnNavx5Get;

            bean.Tweak.GnssSetRateEvent += OnRateSet;
            bean.Tweak.GnssSetGnssEvent += OnGnssSet;
            bean.Tweak.GnssSetNavx5Event += OnNavx5Set;

            _ = bean.Tweak.GetGnssAll();
        }

        protected override void OnDisappearing()
        {
            bean.Tweak.GnssGetRateEvent -= OnRateGet;
            bean.Tweak.GnssGetGnssEvent -= OnGnssGet;
            bean.Tweak.GnssGetNavx5Event -= OnNavx5Get;

            bean.Tweak.GnssSetRateEvent -= OnRateSet;
            bean.Tweak.GnssSetGnssEvent -= OnGnssSet;
            bean.Tweak.GnssSetNavx5Event -= OnNavx5Set;

            base.OnDisappearing();
        }
        #endregion

        #region 交互事件
        void CheckBox_GnssRate_CheckedChanged(object sender, CheckedChangedEventArgs e)
        {
            CheckBox cbx = sender as CheckBox;
            CheckBox[] cbxs = new CheckBox[] { cbxGnss1Hz, cbxGnss2Hz, cbxGnss5Hz, cbxGnss10Hz, cbxGnss18Hz, cbxGnss20Hz };
            foreach (CheckBox c in cbxs)
            {
                c.CheckedChanged -= CheckBox_GnssRate_CheckedChanged;
                c.IsChecked = c == cbx;
                c.CheckedChanged += CheckBox_GnssRate_CheckedChanged;
            }
        }

        async void Button_GnssApply_Clicked(object sender, EventArgs e)
        {
            ResetAllFlags();

            await DoNavx5Set();
            await DoGnssSet();
            await DoRateSet();
        }
        #endregion
    }
}
